﻿using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using System.Threading;
using System.ComponentModel;

namespace FlowControl
{
    /// <summary>
    /// Interaction logic for MainWindow.xaml
    /// </summary>
    public partial class MainWindow : Window
    {
        private DragOb current = new DragOb();          // Actuall object that moving
        private StartProc startProc = new StartProc();  // PROC
        private Hashtable ProcList = new Hashtable();   // objects contener
        private int actId = 666;                        // another ID for object (linking)
        private Point actPos;                           // using to another object pos when drawing line


        public MainWindow()
        {
            InitializeComponent();

            // Add some fake procs - only for test
            ProcList.Add(0, new Test0() { Ident = 0, status = (Label)mainCanvas.FindName("labelStatus_" + 0), progress = (Rectangle)mainCanvas.FindName("rectP_" + 0), statusBox = textBox1 });
            ProcList.Add(1, new Test0() { Ident = 1, status = (Label)mainCanvas.FindName("labelStatus_" + 1), progress = (Rectangle)mainCanvas.FindName("rectP_" + 1), statusBox = textBox1 });
            ProcList.Add(2, new Test0() { Ident = 2, status = (Label)mainCanvas.FindName("labelStatus_" + 2), progress = (Rectangle)mainCanvas.FindName("rectP_" + 2), statusBox = textBox1 });
            ProcList.Add(3, new Test0() { Ident = 3, status = (Label)mainCanvas.FindName("labelStatus_" + 3), progress = (Rectangle)mainCanvas.FindName("rectP_" + 3), statusBox = textBox1 });
            ProcList.Add(4, new Test0() { Ident = 4, status = (Label)mainCanvas.FindName("labelStatus_" + 4), progress = (Rectangle)mainCanvas.FindName("rectP_" + 4), statusBox = textBox1 });

            ((Procs)ProcList[0]).In[0] = new double[,] { { 1.0, 2.0 } };

            /*ProcList.Add(0, new Procs(0, (Canvas)mainCanvas.FindName("obj_0")));
            ProcList.Add(1, new Procs(1, (Canvas)mainCanvas.FindName("obj_1")));
            ProcList.Add(2, new Procs(2, (Canvas)mainCanvas.FindName("obj_2")));
            ProcList.Add(3, new Procs(3, (Canvas)mainCanvas.FindName("obj_3")));
            ProcList.Add(4, new Procs(4, (Canvas)mainCanvas.FindName("obj_4")));*/
        }

        // This method allow to change main status in textbox by other threads
        private delegate void DChangeStatus(string txt);
        private void ChangeStatus(string txt)
        {
            if (this.textBox1.Dispatcher.CheckAccess())
                textBox1.Text = txt;
            else
                textBox1.Dispatcher.Invoke(System.Windows.Threading.DispatcherPriority.Normal, new DChangeStatus(this.ChangeStatus), txt);
        }

        // Graphic-objects events
        private void Canvas_MouseDown(object sender, MouseButtonEventArgs e)
        {
            Point pos = e.GetPosition(current.InputElement);

            // --- DEBUG CODE - This will be simplified

            // If action for process is selected

            if (((Canvas)current.InputElement).Name == "proc1")
            {
                textBox1.Text = "Wybrano akcje dla PROCESU ... ";
                current.InActionProc = true;
                this.current.InputElement.ReleaseMouseCapture();
                this.current.IsDragging = false;
                this.current.InAction = false;

                actPos = e.GetPosition(mainCanvas);     // store actuall position to draw line
            }
            // Standard action for object-object (OUT1)
            else if ((pos.X >= 110 && pos.Y >= 30) && (pos.X <= 150 && pos.Y <= 50))   // if action for object is selected
            {
                textBox1.Text = "Wybrano OUT1 dla obiektu: " + ((Canvas)current.InputElement).Name;
                current.InAction = true;
                current.ActionId = 1;

                this.current.InputElement.ReleaseMouseCapture();
                this.current.IsDragging = false;

                actId = Convert.ToInt32(((Canvas)current.InputElement).Tag);  // store actuall ID of object
                actPos = e.GetPosition(mainCanvas);     // store actuall position to draw line
            }
            // Standard action for object-object (OUT2)
            else if ((pos.X >= 110 && pos.Y >= 50) && (pos.X <= 150 && pos.Y <= 70))   // if action for object is selected
            {
                textBox1.Text = "Wybrano OUT2 dla obiektu: " + ((Canvas)current.InputElement).Name;
                current.InAction = true;
                current.ActionId = 2;

                this.current.InputElement.ReleaseMouseCapture();
                this.current.IsDragging = false;

                actId = Convert.ToInt32(((Canvas)current.InputElement).Tag);  // store actuall ID of object
                actPos = e.GetPosition(mainCanvas);     // store actuall position to draw line
            }
            // Standard action for object-object (OUT3)
            else if ((pos.X >= 110 && pos.Y >= 70) && (pos.X <= 150 && pos.Y <= 90))   // if action for object is selected
            {
                textBox1.Text = "Wybrano OUT3 dla obiektu: " + ((Canvas)current.InputElement).Name;
                current.InAction = true;
                current.ActionId = 3;

                this.current.InputElement.ReleaseMouseCapture();
                this.current.IsDragging = false;

                actId = Convert.ToInt32(((Canvas)current.InputElement).Tag);  // store actuall ID of object
                actPos = e.GetPosition(mainCanvas);     // store actuall position to draw line
            }
            // Standard action for proc-object (IN) - connecting
            else if (((pos.X >= 0) && (pos.X <= 34) && (pos.Y >= 30) && (pos.Y <= 49)) && current.InActionProc)
            {
                int nowId = Convert.ToInt32(((Canvas)current.InputElement).Tag);

                textBox1.Text += " i połączono z obiektem: " + ((Canvas)current.InputElement).Name + "\n";

                this.current.InputElement.ReleaseMouseCapture();
                this.current.IsDragging = false;
                this.current.InActionProc = false;
                this.current.InputElement = null;

                startProc.startObj = ProcList[nowId];

                // Draw line
                Point vvv = e.GetPosition(mainCanvas);
                Line myLine = new Line();
                myLine.Stroke = System.Windows.Media.Brushes.LightSteelBlue;
                myLine.X1 = actPos.X;
                myLine.X2 = vvv.X;
                myLine.Y1 = actPos.Y;
                myLine.Y2 = vvv.Y;
                myLine.StrokeThickness = 2;
                mainCanvas.Children.Add(myLine);
            }
            // Standard action for object-object (IN) - connecting
            else if (current.InAction)
            {
                int In = -1;

                if ((pos.X >= 0) && (pos.X <= 34) && (pos.Y >= 30) && (pos.Y <= 49))
                    In = 0;

                else  if ((pos.X >= 0) && (pos.X <= 34) && (pos.Y >= 50) && (pos.Y <= 68))
                    In = 1;

                else if ((pos.X >= 0) && (pos.X <= 34) && (pos.Y >= 69) && (pos.Y <= 88))
                    In = 2;


                if (In != -1)
                {
                    int nowId = Convert.ToInt32(((Canvas)current.InputElement).Tag);

                    textBox1.Text += " i połączono z obiektem: " + ((Canvas)current.InputElement).Name + " (IN" + (In+1) + ")\n";

                    // Draw line
                    Point vvv = e.GetPosition(mainCanvas);
                    Line myLine = new Line();
                    myLine.Stroke = System.Windows.Media.Brushes.LightSteelBlue;
                    myLine.X1 = actPos.X;
                    myLine.X2 = vvv.X;
                    myLine.Y1 = actPos.Y;
                    myLine.Y2 = vvv.Y;
                    myLine.StrokeThickness = 2;
                    mainCanvas.Children.Add(myLine);


                    if (nowId == actId)
                    {
                        MessageBox.Show("Nie możesz łączyć tego samego obiektu!");
                    }
                    else
                    {
                        ((Procs)ProcList[actId]).AddOut(this.current.ActionId - 1, In, ProcList[nowId]);
                    }

                    this.current.InputElement.ReleaseMouseCapture();
                    this.current.IsDragging = false;
                    this.current.InAction = false;
                    this.current.InputElement = null;
                }
            }
            // Canceling action for proc
            else if (this.current.InActionProc)
            {
                textBox1.Text = "Anulowanie akcji procesu.\n";

                this.current.InputElement.ReleaseMouseCapture();
                this.current.IsDragging = false;
                this.current.InAction = false;
                this.current.InActionProc = false;
                this.current.InputElement = null;
            }
            // Canceling action for object
            else if (this.current.InAction)
            {
                textBox1.Text = "Anulowanie akcji.\n";

                this.current.InputElement.ReleaseMouseCapture();
                this.current.IsDragging = false;
                this.current.InAction = false;
                this.current.InputElement = null;
            }

            // ---

            // Start object-dragging
            else
            {
                this.current.InputElement.CaptureMouse();
                current.X = pos.X;
                current.Y = pos.Y;

                this.current.InAction = false;

                textBox1.Text = "Aktualny obiekt: " + ((Canvas)current.InputElement).Name + "\n";
            }
        }

        private void Canvas_MouseUp(object sender, MouseButtonEventArgs e)
        {
            // Drop object, if it isn't action for proc or object
            if ((this.current.InputElement != null) && !this.current.InAction && !this.current.InActionProc)
            {
                this.current.InputElement.ReleaseMouseCapture();
                this.current.IsDragging = false;

                textBox1.Text = "Opuszczono obiekt: " + ((Canvas)current.InputElement).Name + "\n";
                this.current.InputElement = null;
            }
        }

        private void Canvas_MouseMove(object sender, MouseEventArgs e)
        {
            // Set flag for mouse-down action
            if (e.LeftButton == MouseButtonState.Pressed)
                this.current.IsDragging = true;

            // Object moving
            if (this.current.IsDragging && !this.current.InAction && !this.current.InActionProc && (current.InputElement != null))
            {
                Canvas obj = (Canvas)current.InputElement;
                Point pos = e.GetPosition((IInputElement)sender);
                TranslateTransform ppp = new TranslateTransform();

                ppp.X = pos.X - current.X;
                ppp.Y = pos.Y - current.Y;

                obj.RenderTransform = ppp;

                textBox1.Text = "Przenosze obiekt: " + obj.Name + " ; X: " + Convert.ToString(ppp.X) + " ; Y: " + Convert.ToString(ppp.Y) + " ; OffsetX: " + current.X + " ; OffsetY: " + current.Y + "\n";
            }
        }

        private void startDrag_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
        {
            // Store reference of object that moving
            this.current.InputElement = (IInputElement)sender;

            // Send information to properties window
            labelProp.Content = ((Canvas)sender).Name;

            if (((Procs)ProcList[Convert.ToInt32(((Canvas)sender).Tag)]).ViewOut(0) == null)
                labelOut1.Content = "<brak>";
            else
                labelOut1.Content = "obj_" + ((Procs)((Procs)ProcList[Convert.ToInt32(((Canvas)sender).Tag)]).ViewOut(0)).Ident;


            if (((Procs)ProcList[Convert.ToInt32(((Canvas)sender).Tag)]).ViewOut(1) == null)
                labelOut2.Content = "<brak>";
            else
                labelOut2.Content = "obj_" + ((Procs)((Procs)ProcList[Convert.ToInt32(((Canvas)sender).Tag)]).ViewOut(1)).Ident;


            if (((Procs)ProcList[Convert.ToInt32(((Canvas)sender).Tag)]).ViewOut(2) == null)
                labelOut3.Content = "<brak>";
            else
                labelOut3.Content = "obj_" + ((Procs)((Procs)ProcList[Convert.ToInt32(((Canvas)sender).Tag)]).ViewOut(2)).Ident;
        }

        private void button2_Click(object sender, RoutedEventArgs e)
        {
            // Reset objects stats and progress
            for (int i = 0; i < ProcList.Count; i++)
            {
                Label status = (Label)mainCanvas.FindName("labelStatus_" + i);
                status.Content = "Status: ---";

                Rectangle progress = (Rectangle)mainCanvas.FindName("rectP_" + i);
                progress.Width = 0;
            }

            // Start procn here.
            Thread T = new Thread(Start);
            T.IsBackground = true;
            T.Start();
        }
        
        // Thread of proc-obj
        private void Start()
        {
            ChangeStatus("# Uruchomiono wątek nr " + Thread.CurrentThread.ManagedThreadId.ToString() + "\n");

            if (startProc.startObj != null)
                ((Procs)startProc.startObj).Next();   // reaction start!
            else
            {
                MessageBox.Show("Przypisz obiekt do procesu!");
            }
        }
    }
}
